home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / os2 / ue311gcc.zip / MSDOS.C < prev    next >
C/C++ Source or Header  |  1992-12-30  |  28KB  |  1,169 lines

  1. /*    MSDOS.C:    Operating specific I/O and Spawning functions
  2.             under the MS/PCDOS operating system
  3.             for MicroEMACS 3.10
  4.             (C)Copyright 1988 by Daniel M. Lawrence
  5. */
  6.  
  7. #include        <stdio.h>
  8. #include    <dos.h>
  9. #include    <fcntl.h>
  10. #include    <sys/stat.h>
  11. #include    "estruct.h"
  12. #include    "eproto.h"
  13.  
  14. #ifdef    MSDOS
  15. #include        "edef.h"
  16. #include    "elang.h"
  17.  
  18. /* The Mouse driver only works with typeahead defined */
  19. #if    MOUSE
  20. #undef    TYPEAH
  21. #define    TYPEAH    1
  22. #endif
  23.  
  24. #if  TURBO
  25. #include <conio.h>
  26. #include <dir.h>
  27. #include <dos.h>
  28. #include <bios.h>
  29. #include <fcntl.h>
  30. #include <stat.h>
  31.  
  32. struct ffblk fileblock;    /* structure for directory searches */
  33. #endif
  34. #if    MSC | ZTC
  35. #include <dos.h>
  36.  
  37. struct find_t fileblock;    /* structure for directory searches */
  38. #endif
  39.  
  40. #if     LATTICE | MSC | DTL | TURBO | AZTEC | MWC | ZTC | GCC
  41. union REGS rg;        /* cpu register for use of DOS calls */
  42. struct SREGS segreg;    /* cpu segment registers         */
  43. int nxtchar = -1;    /* character held from type ahead    */
  44. #endif
  45.  
  46. #if    MSC | TURBO
  47. #include    <process.h>
  48. #endif
  49.  
  50. /*    Some global variable    */
  51. #define INBUFSIZ    40
  52. static int mexist;    /* is the mouse driver installed? */
  53. static int nbuttons;    /* number of buttons on the mouse */
  54. static int oldbut;    /* Previous state of mouse buttons */
  55.  
  56. PASCAL NEAR execprog(char *cmd);
  57.  
  58. /*    input buffers and pointers    */
  59.  
  60. #define    IBUFSIZE    64    /* this must be a power of 2 */
  61.  
  62. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  63. int in_next = 0;        /* pos to retrieve next input character */
  64. int in_last = 0;        /* pos to place most recent input character */
  65.  
  66. in_init()    /* initialize the input buffer */
  67.  
  68. {
  69.     in_next = in_last = 0;
  70. }
  71.  
  72. in_check()    /* is the input buffer non-empty? */
  73.  
  74. {
  75.     if (in_next == in_last)
  76.         return(FALSE);
  77.     else
  78.         return(TRUE);
  79. }
  80.  
  81. in_put(event)
  82.  
  83. int event;    /* event to enter into the input buffer */
  84.  
  85. {
  86.     in_buf[in_last++] = event;
  87.     in_last &= (IBUFSIZE - 1);
  88. }
  89.  
  90. int in_get()    /* get an event from the input buffer */
  91.  
  92. {
  93.     register int event;    /* event to return */
  94.  
  95.     event = in_buf[in_next++];
  96.     in_next &= (IBUFSIZE - 1);
  97.     return(event);
  98. }
  99.  
  100. /*
  101.  * This function is called once to set up the terminal device streams.
  102.  */
  103.  
  104. PASCAL NEAR ttopen()
  105.  
  106. {
  107. #if    MOUSE
  108.     long miaddr;    /* mouse interupt routine address */
  109. #endif
  110.  
  111.     /* on all screens we are not sure of the initial position
  112.        of the cursor                    */
  113.     ttrow = 999;
  114.     ttcol = 999;
  115.  
  116. #if    MOUSE
  117.     /* check if the mouse drive exists first */
  118.     rg.x.ax = 0x3533;    /* look at the interrupt 33 address */
  119. #if    MSC | TURBO | DTL | LATTICE | MWC | GCC
  120.     int86x(0x21, &rg, &rg, &segreg);
  121.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  122.     if (miaddr == 0 || *(char * far)miaddr == 0xcf) {
  123. #endif
  124. #if    ZTC
  125.     int86x(0x21, &rg, &rg, &segreg);
  126.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  127.     if (miaddr == 0 || *(char far *)miaddr == 0xcf) {
  128. #endif
  129. #if    AZTEC
  130.     sysint(0x21, &rg, &rg);
  131.     miaddr = (((long)rg.x.es) << 16) + (long)rg.x.bx;
  132.     if (miaddr == 0 || *(char *)miaddr == 0xcf) {
  133. #endif
  134.         mexist = FALSE;
  135.         return;
  136.     }
  137.  
  138.     /* and then check for the mouse itself */
  139.     rg.x.ax = 0;        /* mouse status flag */
  140.     int86(0x33, &rg, &rg);    /* check for the mouse interupt */
  141.     mexist = (rg.x.ax != 0);
  142.     nbuttons = rg.x.bx;
  143.  
  144.     /* initialize our character input queue */
  145.     in_init();
  146.     if (mexist == FALSE)
  147.         return;
  148.  
  149.     /* if the mouse exists.. get it in the upper right corner */
  150.     rg.x.ax = 4;        /* set mouse cursor position */
  151.     rg.x.cx = (term.t_ncol - 1) << 3;    /* last col of display */
  152.     rg.x.dx = 0;        /* top row */
  153.     int86(0x33, &rg, &rg);
  154.  
  155.     /* and set its attributes */
  156.     rg.x.ax = 10;        /* set text cursor */
  157.     rg.x.bx = 0;        /* software text cursor please */
  158.     rg.x.cx = 0x77ff;    /* screen mask */
  159.     rg.x.dx = 0x7700;    /* cursor mask */
  160.     int86(0x33, &rg, &rg);
  161. #else    /* !MOUSE */
  162.     mexist = 0;
  163. #endif    /* !MOUSE */
  164. }
  165.  
  166. maxlines(lines)        /* set number of vertical rows for mouse */
  167.  
  168. int lines;    /* # of vertical lines */
  169.  
  170. {
  171. #if    MOUSE
  172.     if (mexist) {
  173.         rg.x.ax = 8;        /* set min/max vertical cursor position */
  174.         rg.x.cx = 0;        /* start at 0 */
  175.         rg.x.dx = (lines - 1)<<3; /* end at the end */
  176.         int86(0x33, &rg, &rg);
  177.     }
  178. #endif
  179. }
  180.  
  181. /*
  182.  * This function gets called just before we go back home to the command
  183.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  184.  * Another no-operation on CPM.
  185.  */
  186. PASCAL NEAR ttclose()
  187. {
  188.     /* nothing here! */
  189. }
  190.  
  191. /*
  192.  * Write a character to the display. On VMS, terminal output is buffered, and
  193.  * we just put the characters in the big array, after checking for overflow.
  194.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  195.  * MS-DOS (use the very very raw console output routine).
  196.  */
  197.  
  198. PASCAL NEAR ttputc(c)
  199.  
  200. int c;
  201.  
  202. {
  203. #if     MWC
  204.         putcnb(c);
  205. #endif
  206.  
  207. #if    (LATTICE | AZTEC | TURBO | MSC | ZTC | GCC) & ~IBMPC
  208.     bdos(6, c, 0);
  209. #endif
  210. }
  211.  
  212. /*
  213.  * Flush terminal buffer. Does real work where the terminal output is buffered
  214.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  215.  */
  216. PASCAL NEAR ttflush()
  217. {
  218. }
  219.  
  220. int doschar()    /* call the dos to get a char */
  221.  
  222. {
  223. #if ATKBD    /* AT-style extended keyboard with grey keys */
  224.  
  225.     rg.h.ah = 0x10;            /* Get Keyboard Input call */
  226.     int86(0x16, &rg, &rg);
  227.  
  228.     /* function key!! */
  229.     if (rg.h.al == 0 || rg.h.al == 0xE0) {
  230.  
  231.         rg.h.cl = rg.h.ah;    /* swap scan code and value */
  232.         rg.h.ch = rg.h.al;
  233.         rg.x.cx = extcode(rg.x.cx);
  234.         in_put(rg.h.ch & 255);    /* prefix byte */
  235.         in_put(rg.h.cl & 255);    /* event code byte */
  236.         return(0);        /* extended escape sequence */
  237.     }
  238.     return(rg.h.al & 255);
  239. #else
  240.  
  241. #if    TURBO && HP150 == 0
  242. /*    Added 8/13/89 by DRK to get Turbo C version to use BIOS for
  243.     keyboard input. Low byte of k has first byte of extended scan
  244.     (ASCII value for reg. char, 0 for extended char), high byte has
  245.     extended key scan code.
  246. */
  247.  
  248.     unsigned k = (unsigned)bioskey(0);
  249.     unsigned c;        /* Extended character to return. */
  250.  
  251.     if ((k & 0xFF) == 0) {    /* Check for extended key. */
  252.                 /* Convert extended key scan code to a
  253.                    uEMACS internal form. */
  254.         c = extcode(k >> 8);
  255.         in_put(c >> 8);    /* Report prefix and event code bytes. */
  256.         in_put(c & 0xFF);
  257.         return(0);    /* Return extended escape sequence. */
  258.     }
  259.     return (k & 0xFF);    /* Return regular ASCII value. */
  260.  
  261. #else
  262.     register unsigned int c;    /* extended character to return */ 
  263.  
  264.     rg.h.ah = 7;        /* dos Direct Console Input call */
  265.     intdos(&rg, &rg);
  266. #if    HP150 == 0        /* this translation level is deeper on the HP150 */
  267.     if (rg.h.al == 0) {    /* function key!! */
  268.         rg.h.ah = 7;    /* get the next character */
  269.         intdos(&rg, &rg);
  270.         c = extcode(rg.h.al);
  271.         in_put(c >> 8);        /* prefix byte */
  272.         in_put(c & 255);    /* event code byte */
  273.         return(0);        /* extended escape sequence */
  274.     }
  275. #endif
  276.     return(rg.h.al & 255);
  277. #endif
  278. #endif
  279. }
  280.  
  281. /*
  282.  * Read a character from the terminal, performing no editing and doing no echo
  283.  * at all. Also mouse events are forced into the input stream here.
  284.  */
  285. PASCAL NEAR ttgetc()
  286.  
  287. {
  288.     register int c;        /* character read */
  289.  
  290. ttc:    /* return any keystrokes waiting in the
  291.        type ahead buffer */
  292.     if (in_check())
  293.         return(in_get());
  294.  
  295. #if    TYPEAH
  296.     if (typahead())
  297.         return(doschar());
  298.  
  299.     /* with no mouse, this is a simple get char routine */
  300.     if (mexist == FALSE || mouseflag == FALSE)
  301.         return(doschar());
  302.  
  303. #if    MOUSE
  304.     /* turn the mouse cursor on */
  305.     rg.x.ax = 1;    /* Show Cursor */
  306.     int86(0x33, &rg, &rg);
  307.  
  308.     /* loop waiting for something to happen */
  309.     while (TRUE) {
  310.         if (typahead())
  311.             break;
  312.         if (checkmouse())
  313.             break;
  314.     }
  315.  
  316.     /* turn the mouse cursor back off */
  317.     rg.x.ax = 2;    /* Hide Cursor */
  318.     int86(0x33, &rg, &rg);
  319.  
  320.     goto ttc;
  321. #endif    /* MOUSE */
  322. #else    /* TYPEAH */
  323.     return(doschar());
  324. #endif    /* TYPEAH */
  325. }
  326.  
  327. #if    MOUSE
  328. checkmouse()
  329.  
  330. {
  331.     register int k;        /* current bit/button of mouse */
  332.     register int event;    /* encoded mouse event */
  333.     int mousecol;        /* current mouse column */
  334.     int mouserow;        /* current mouse row */
  335.     int sstate;        /* current shift key status */
  336.     int newbut;        /* new state of the mouse buttons */
  337.  
  338.     /* check to see if any mouse buttons are different */
  339.     rg.x.ax = 3;    /* Get button status and mouse position */
  340.     int86(0x33, &rg, &rg);
  341.     newbut = rg.x.bx;
  342.     if (strcmp(sres, "CGA40") == 0)
  343.         mousecol = rg.x.cx >> 4;
  344.     else /* if (term.t_ncol == 80) */
  345.         mousecol = rg.x.cx >> 3;
  346.     mouserow = (rg.x.dx >> 3);
  347.  
  348.     /* only notice changes */
  349.     if (oldbut == newbut)
  350.         return(FALSE);
  351.  
  352.     /* only on screen presses are legit! */
  353.     if (mousecol < 0)
  354.         mousecol = 0;
  355.     if (mouserow < 0)
  356.         mouserow = 0;
  357.  
  358.     /* get the shift key status as well */
  359.     sstate = 0;
  360.     rg.h.ah = 2;    /* return current shift status */
  361.     int86(0x16, &rg, &rg);
  362.     sstate = rg.h.al;
  363.  
  364.     for (k=1; k != (1 << nbuttons); k = k<<1) {
  365.         /* For each button on the mouse */
  366.         if ((oldbut&k) != (newbut&k)) {
  367.             /* This button changed, generate an event */
  368.             in_put(0);
  369.             in_put(MOUS >> 8);
  370.             in_put(mousecol);
  371.             in_put(mouserow);
  372.  
  373.             event = ((newbut&k) ? 0 : 1);    /* up or down? */
  374.             if (k == 2)            /* center button? */
  375.                 event += 4;
  376.             if (k == 4)            /* right button? */
  377.                 event += 2;
  378.             if (sstate & 3)            /* shifted */
  379.                 event += 'A';
  380.             else if (sstate & 4)        /* controled? */
  381.                 event += 1;
  382.             else
  383.                 event += 'a';        /* plain */
  384.             in_put(event);
  385.             oldbut = newbut;
  386.             return(TRUE);
  387.         }
  388.     }
  389.     return(FALSE);
  390. }
  391. #endif
  392.  
  393. #if    TYPEAH
  394. /* typahead:    Check to see if any characters are already in the
  395.         keyboard buffer
  396. */
  397.  
  398. PASCAL NEAR typahead()
  399.  
  400. {
  401.     int flags;    /* cpu flags from dos call */
  402.  
  403. #if    TURBO && HP150 == 0 && ATKBD == 0
  404.     if (bioskey(1) == 0)
  405.         return FALSE;
  406.     else
  407.         return TRUE;
  408. #else
  409.     rg.x.ax = 0x4406;    /* IOCTL input status */
  410.     rg.x.bx = 0;        /* File handle = stdin */
  411. #if    MSC | DTL
  412.     int86(0x21,&rg,&rg);
  413.     flags = rg.h.al;
  414. #else
  415. #if    LATTICE | AZTEC | TURBO | ZTC | GCC
  416.     flags = intdos(&rg, &rg);
  417. #else
  418.     intcall(&rg, &rg, 0x21);
  419.     flags = rg.x.flags;
  420. #endif
  421. #endif
  422.     if (flags & 1)        /* AL = 0xFF if ready */
  423.         return(TRUE);
  424.     else
  425.         return(FALSE);
  426. #endif
  427. }
  428. #endif
  429.  
  430. /*
  431.  * Create a subjob with a copy of the command intrepreter in it. When the
  432.  * command interpreter exits, mark the screen as garbage so that you do a full
  433.  * repaint. Bound to "^X C".
  434.  */
  435.  
  436. PASCAL NEAR spawncli(f, n)
  437.  
  438. int f, n;
  439.  
  440. {
  441.     /* don't allow this command if restricted */
  442.     if (restflag)
  443.         return(resterr());
  444.  
  445.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  446.         TTflush();
  447.     TTkclose();
  448.     shellprog("");
  449. #if    WINDOW_TEXT
  450.     refresh_screen(first_screen);
  451. #endif
  452.     TTkopen();
  453.         sgarbf = TRUE;
  454.         return(TRUE);
  455. }
  456.  
  457. /*
  458.  * Run a one-liner in a subjob. When the command returns, wait for a single
  459.  * character to be typed, then mark the screen as garbage so a full repaint is
  460.  * done. Bound to "C-X !".
  461.  */
  462. PASCAL NEAR spawn(f, n)
  463.  
  464. int f, n;
  465.  
  466. {
  467.         register int s;
  468.         char line[NLINE];
  469.  
  470.     /* don't allow this command if restricted */
  471.     if (restflag)
  472.         return(resterr());
  473.  
  474.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  475.                 return(s);
  476.     movecursor(term.t_nrow - 1, 0);
  477.     TTkclose();
  478.         shellprog(line);
  479.     TTkopen();
  480.  
  481.     /* if we are interactive, pause here */
  482.     if (clexec == FALSE) {
  483.         printf(TEXT227);
  484. /*            "\n--- Press any key to Continue ---" */
  485. #if    GCC
  486.         (void) fflush (stdout);
  487. #endif
  488.         tgetc();
  489.         }
  490. #if    WINDOW_TEXT
  491.     refresh_screen(first_screen);
  492. #endif
  493.         sgarbf = TRUE;
  494.         return (TRUE);
  495. }
  496.  
  497. /*
  498.  * Run an external program with arguments. When it returns, wait for a single
  499.  * character to be typed, then mark the screen as garbage so a full repaint is
  500.  * done. Bound to "C-X $".
  501.  */
  502.  
  503. PASCAL NEAR execprg(f, n)
  504.  
  505. {
  506.         register int s;
  507.         char line[NLINE];
  508.  
  509.     /* don't allow this command if restricted */
  510.     if (restflag)
  511.         return(resterr());
  512.  
  513.         if ((s=mlreply("$", line, NLINE)) != TRUE)
  514.                 return(s);
  515.     movecursor(term.t_nrow - 1, 0);
  516.     TTkclose();
  517.         execprog(line);
  518. #if    WINDOW_TEXT
  519.     refresh_screen(first_screen);
  520. #endif
  521.     TTkopen();
  522.     /* if we are interactive, pause here */
  523.     if (clexec == FALSE) {
  524.             mlputs(TEXT6);
  525. /*                     "\r\n\n[End]" */
  526.             tgetc();
  527.         }
  528.         sgarbf = TRUE;
  529.         return (TRUE);
  530. }
  531.  
  532. /*
  533.  * Pipe a one line command into a window
  534.  * Bound to ^X @
  535.  */
  536. PASCAL NEAR pipecmd(f, n)
  537.  
  538. int f, n;
  539.  
  540. {
  541.     register WINDOW *wp;    /* pointer to new window */
  542.     register BUFFER *bp;    /* pointer to buffer to zot */
  543.     register char *tmp;    /* ptr to TMP DOS environment variable */
  544.     FILE *fp;
  545.         char line[NLINE];    /* command line send to shell */
  546.     static char bname[] = "command";
  547.     static char filnam[NSTRING] = "command";
  548.     union REGS regs;    /* parameters for dos call */
  549.     char swchar;
  550.     char slash[2];
  551.     int fd, oldfd;        /* for output redirection    */
  552.     char *getenv();
  553. #if    GCC
  554.     char *shell;        /* Name of system command processor */
  555.     char *p;            /* -> COMSPEC                        */
  556. #endif
  557.  
  558.     /* don't allow this command if restricted */
  559.     if (restflag)
  560.         return(resterr());
  561.  
  562.     /*  detect current switch character and set us up to use it */
  563. #if    !GCC
  564.     regs.h.ah = 0x37;    /*  get setting data  */
  565.     regs.h.al = 0x00;    /*  get switch character  */
  566.     intdos(®s, ®s);
  567.     swchar = (char)regs.h.dl;
  568. #else
  569.     /*  get name of system shell  */
  570.     if ((shell = getenv("COMSPEC")) == NULL) {
  571.         return(FALSE);        /*  No shell located  */
  572.     }
  573.  
  574.     if ((p = strrchr (shell, '/')) == 0)
  575.         p = shell;
  576.  
  577.     /* See if shell is a UNIX emulation. */
  578.         
  579.     p++;
  580.     if (strncmp (p, "sh", 2) == 0)
  581.         swchar = '-';
  582.     else
  583.         swchar = '/';
  584.  
  585. #endif
  586.  
  587.     if (swchar == '-')
  588.         *slash = '/';
  589.     else
  590.         *slash = '\\';
  591.  
  592.     *(slash + 1) = '\0';
  593.  
  594.     if ((tmp = getenv("TMP")) == NULL)
  595.         filnam[0] = 0;
  596.     else {
  597.         strcpy(filnam, tmp);
  598.         if (filnam[strlen(filnam) - 1] != *slash)
  599.             strcat(filnam, slash);
  600.          }
  601.     strcat(filnam,"command");
  602.  
  603.     /* Open the output file and redirect stdout. */
  604.  
  605.     if ((fd = open ("/tmp/command",
  606.             O_CREAT | O_RDWR, S_IREAD | S_IWRITE)) == -1)
  607.         return (FALSE);
  608.  
  609.     oldfd = dup (1);
  610.     close (1);
  611.     (void) dup (fd);
  612.     close (fd);
  613. #if    0
  614.     oldfd = dup (1);
  615.     dup2 (fd, 1);
  616.     close (fd);
  617. #endif
  618.  
  619.     /* get the command to pipe in */
  620.         if (mlreply("@", line + 1, NLINE) != TRUE)
  621.                 return(FALSE);
  622.  
  623.     /* get rid of the command output buffer if it exists */
  624.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  625.         /* try to make sure we are off screen */
  626.         wp = wheadp;
  627.         while (wp != NULL) {
  628.             if (wp->w_bufp == bp) {
  629.                 onlywind(FALSE, 1);
  630.                 break;
  631.             }
  632.             wp = wp->w_wndp;
  633.         }
  634.         /* get rid of the existing command buffer */
  635.         if (zotbuf(bp) != TRUE)
  636.             return(FALSE);
  637.     }
  638.  
  639.     /* redirect the command output to the output file */
  640.  
  641.     *line = '\'';
  642.     strcat (line, "'");
  643. #if    0
  644.     strcat(line, " >>");
  645.     strcat(line, filnam);
  646. #endif
  647.     movecursor(term.t_nrow - 1, 0);
  648.  
  649.     /* execute the command */
  650.     TTkclose();
  651. #if    GCC
  652.     shellprog(line);
  653. #else
  654.     system (line);
  655. #endif
  656.     (void) close (1);
  657.     (void) dup (oldfd);
  658.     (void) close (oldfd);
  659. #if    0
  660.     dup2 (oldfd, 1);    /* restore stdout            */
  661.     close (oldfd);
  662.     close (fd);
  663. #endif
  664. #if    WINDOW_TEXT
  665.     refresh_screen(first_screen);
  666. #endif
  667.     TTkopen();
  668.         sgarbf = TRUE;
  669.  
  670.         /* did the output file get generated? */
  671.     if ((fp = fopen(filnam, "r")) == NULL)
  672.         return(FALSE);
  673.     fclose(fp);
  674.  
  675.     /* split the current window to make room for the command output */
  676.     if (splitwind(FALSE, 1) == FALSE)
  677.             return(FALSE);
  678.  
  679.     /* and read the stuff in */
  680.     if (getfile(filnam, FALSE) == FALSE)
  681.         return(FALSE);
  682.  
  683.     /* make this window in VIEW mode, update all mode lines */
  684.     curwp->w_bufp->b_mode |= MDVIEW;
  685.     wp = wheadp;
  686.     while (wp != NULL) {
  687.         wp->w_flag |= WFMODE;
  688.         wp = wp->w_wndp;
  689.     }
  690.  
  691.     /* and get rid of the temporary file */
  692.     unlink(filnam);
  693.     return(TRUE);
  694. }
  695.  
  696. /*
  697.  * filter a buffer through an external DOS program
  698.  * Bound to ^X #
  699.  */
  700. PASCAL NEAR filter(f, n)
  701.  
  702. int f, n;
  703.  
  704. {
  705.         register int    s;    /* return status from CLI */
  706.     register BUFFER *bp;    /* pointer to buffer to zot */
  707.         char line[NLINE];    /* command line send to shell */
  708.     char tmpnam[NFILEN];    /* place to store real file name */
  709.     static char bname1[] = "fltinp";
  710.  
  711.     static char filnam1[] = "fltinp";
  712.     static char filnam2[] = "fltout";
  713.  
  714.     /* don't allow this command if restricted */
  715.     if (restflag)
  716.         return(resterr());
  717.  
  718.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  719.         return(rdonly());    /* we are in read only mode    */
  720.  
  721.     /* get the filter name and its args */
  722.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  723.                 return(s);
  724.  
  725.     /* setup the proper file names */
  726.     bp = curbp;
  727.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  728.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  729.  
  730.     /* write it out, checking for errors */
  731.     if (writeout(filnam1, "w") != TRUE) {
  732.         mlwrite(TEXT2);
  733. /*                      "[Cannot write filter file]" */
  734.         strcpy(bp->b_fname, tmpnam);
  735.         return(FALSE);
  736.     }
  737.  
  738.     strcat(line," <fltinp >fltout");
  739.     movecursor(term.t_nrow - 1, 0);
  740.     TTkclose();
  741.         shellprog(line);
  742. #if    WINDOW_TEXT
  743.     refresh_screen(first_screen);
  744. #endif
  745.     TTkopen();
  746.         sgarbf = TRUE;
  747.     s = TRUE;
  748.  
  749.     /* on failure, escape gracefully */
  750.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  751.         mlwrite(TEXT3);
  752. /*                      "[Execution failed]" */
  753.         strcpy(bp->b_fname, tmpnam);
  754.         unlink(filnam1);
  755.         unlink(filnam2);
  756.         return(s);
  757.     }
  758.  
  759.     /* reset file name */
  760.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  761.     bp->b_flag |= BFCHG;        /* flag it as changed */
  762.  
  763.     /* and get rid of the temporary file */
  764.     unlink(filnam1);
  765.     unlink(filnam2);
  766.     return(TRUE);
  767. }
  768.  
  769. #if    LATTICE
  770. extern int _oserr;
  771. #endif
  772.  
  773. #if    AZTEC | MWC
  774. extern int errno;
  775. #endif
  776.  
  777. #if    MSC
  778. extern int _doserrno;
  779. #endif
  780.  
  781. /*    SHELLPROG: Execute a command in a subshell        */
  782.  
  783. PASCAL NEAR shellprog(cmd)
  784.  
  785. char *cmd;    /*  Incoming command line to execute  */
  786.  
  787. {
  788.     char *shell;        /* Name of system command processor */
  789. #if    GCC
  790.     char *p;            /* -> COMSPEC                        */
  791. #endif
  792.     char swchar;        /* switch character to use */
  793.     union REGS regs;    /* parameters for dos call */
  794.     char comline[NSTRING];    /* constructed command line */
  795.     char *getenv();
  796.  
  797. #if    !GCC                /* causes exception 13 in djgcc            */
  798.     /*  detect current switch character and set us up to use it */
  799.     regs.h.ah = 0x37;    /*  get setting data  */
  800.     regs.h.al = 0x00;    /*  get switch character  */
  801.     intdos(®s, ®s);
  802.     swchar = (char)regs.h.dl;
  803. #endif
  804.  
  805.     /*  get name of system shell  */
  806.     if ((shell = getenv("COMSPEC")) == NULL) {
  807.         return(FALSE);        /*  No shell located  */
  808.     }
  809.  
  810. #if    GCC
  811.     if ((p = strrchr (shell, '/')) == 0)
  812.         p = shell;
  813.  
  814.     /* See if shell is a UNIX emulation. */
  815.         
  816.     p++;
  817.     if (strncmp (p, "sh", 2) == 0)
  818.         swchar = '-';
  819.     else
  820.         swchar = '/';
  821.  
  822. #endif
  823.  
  824.     /* trim leading whitespace off the command */
  825.     while (*cmd == ' ' || *cmd == '\t')    /*  find out if null command */
  826.         cmd++;
  827.  
  828.     /**  If the command line is not empty, bring up the shell  **/
  829.     /**  and execute the command.  Otherwise, bring up the     **/
  830.     /**  shell in interactive mode.   **/
  831.  
  832.     if (*cmd) {
  833.         strcpy(comline, shell);
  834.         strcat(comline, " ");
  835.         comline[strlen(comline) + 1] = 0;
  836.         comline[strlen(comline)] = swchar;
  837.         strcat(comline, "c ");
  838.         if (swchar == '-' && *cmd != '\'')
  839.             strcat (comline, "'");        /* single quotes for UNIX shell    */
  840.             
  841.         strcat(comline, cmd);
  842.         if (swchar == '-' && *cmd != '\'')
  843.             strcat (comline, "'");
  844.             
  845.         return(execprog(comline));
  846.     } else
  847.         return(execprog(shell));
  848. }
  849.  
  850. /*    EXECPROG:    A function to execute a named program
  851.             with arguments
  852. */
  853.  
  854. #if    LATTICE | AZTEC | MWC
  855. #define    CFLAG    1
  856. #endif
  857.  
  858. PASCAL NEAR execprog(cmd)
  859.  
  860. char *cmd;    /*  Incoming command line to execute  */
  861.  
  862. {
  863. #if    GCC
  864.     return (system (cmd));
  865. #else
  866.     char *sp;        /* temporary string pointer */
  867.     char f1[38];        /* FCB1 area (not initialized */
  868.     char f2[38];        /* FCB2 area (not initialized */
  869.     char prog[NSTRING];    /* program filespec */
  870.     char tail[NSTRING];    /* command tail with length byte */
  871.     union REGS regs;    /* parameters for dos call  */
  872. #if    MWC == 0
  873.     struct SREGS segreg;    /* segment registers for dis call */
  874. #endif
  875.     struct Pblock {        /* EXEC parameter block */
  876.         short envptr;    /* 2 byte pointer to environment string */
  877.         char *cline;    /* 4 byte pointer to command line */
  878.         char *fcb1;    /* 4 byte pointer to FCB at PSP+5Ch */
  879.         char *fcb2;    /* 4 byte pointer to FCB at PSP+6Ch */
  880.     } pblock;
  881.  
  882.     /* parse the command name from the command line */
  883.     sp = prog;
  884.     while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
  885.         *sp++ = *cmd++;
  886.     *sp = 0;
  887.  
  888.     /* and parse out the command tail */
  889.     while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
  890.         ++cmd;
  891.     *tail = (char)(strlen(cmd)); /* record the byte length */
  892.     strcpy(&tail[1], cmd);
  893.     strcat(&tail[1], "\r");
  894.  
  895.     /* look up the program on the path trying various extentions */
  896.     if ((sp = flook(prog, TRUE)) == NULL)
  897.         if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
  898.             strcpy(&prog[strlen(prog)-4], ".com");
  899.             if ((sp = flook(prog, TRUE)) == NULL)
  900.                 return(FALSE);
  901.         }
  902.     strcpy(prog, sp);
  903.  
  904. #if    MWC == 0 && GCC == 0
  905.     /* get a pointer to this PSPs environment segment number */
  906.     segread(&segreg);
  907. #endif
  908.  
  909.     /* set up the EXEC parameter block */
  910.     pblock.envptr = 0;    /* make the child inherit the parents env */
  911.     pblock.fcb1 = f1;        /* point to a blank FCB */
  912.     pblock.fcb2 = f2;        /* point to a blank FCB */
  913.         pblock.cline = tail;        /* parameter line pointer */
  914.  
  915.     /* and make the call */
  916.     regs.h.ah = 0x4b;    /* EXEC Load or Execute a Program */
  917.     regs.h.al = 0x00;    /* load end execute function subcode */
  918. #if    AZTEC | MWC
  919.     regs.x.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  920.     regs.x.dx = (unsigned int)(prog);
  921.     regs.x.es = regs.x.ds;
  922.     /*regs.x.es = ((unsigned long)(&pblock) >> 16);    * set up param block ptr */
  923.     regs.x.bx = (unsigned int)(&pblock);
  924. #endif
  925. #if    LATTICE | MSC | TURBO | DTL | ZTC | GCC
  926.     segreg.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  927.     regs.x.dx = (unsigned int)(prog);
  928.     segreg.es = ((unsigned long)(&pblock) >> 16);    /* set up param block ptr */
  929.     regs.x.bx = (unsigned int)(&pblock);
  930. #endif
  931.  
  932. #if    NOVELL
  933.     rval = execpr(prog, &pblock);
  934. #endif
  935.     
  936. #if    LATTICE && (NOVELL == 0)
  937.     if ((intdosx(®s, ®s, &segreg) & CFLAG) == 0) {
  938.         regs.h.ah = 0x4d;    /* get child process return code */
  939.         intdos(®s, ®s);    /* go do it */
  940.         rval = regs.x.ax;    /* save child's return code */
  941.     } else
  942.         rval = -_oserr;        /* failed child call */
  943. #endif
  944. #if    AZTEC && (NOVELL == 0)
  945.     if ((sysint(0x21, ®s, ®s) & CFLAG) == 0) {
  946.         regs.h.ah = 0x4d;    /* get child process return code */
  947.         sysint(0x21, ®s, ®s);    /* go do it */
  948.         rval = regs.x.ax;    /* save child's return code */
  949.     } else
  950.         rval = -errno;        /* failed child call */
  951. #endif
  952. #if    MWC && (NOVELL == 0)
  953.     intcall(®s, ®s, DOSINT);
  954.     if ((regs.x.flags & CFLAG) == 0) {
  955.         regs.h.ah = 0x4d;    /* get child process return code */
  956.         intcall(®s, ®s, DOSINT);    /* go do it */
  957.         rval = regs.x.ax;    /* save child's return code */
  958.     } else
  959.         rval = -errno;        /* failed child call */
  960. #endif
  961. #if    (TURBO | MSC | DTL | ZTC | GCC) && (NOVELL == 0)
  962.     intdosx(®s, ®s, &segreg);
  963.     if (regs.x.cflag == 0) {
  964.         regs.h.ah = 0x4d;    /* get child process return code */
  965.         intdos(®s, ®s);    /* go do it */
  966.         rval = regs.x.ax;    /* save child's return code */
  967.     } else
  968. #if    GCC
  969.         rval = -1;
  970. #else
  971.         rval = -_doserrno;    /* failed child call */
  972. #endif
  973. #endif
  974.     return((rval < 0) ? FALSE : TRUE);
  975. #endif
  976. }
  977.  
  978. /* return a system dependant string with the current time */
  979.  
  980. char *PASCAL NEAR timeset()
  981.  
  982. {
  983. #if    MWC | TURBO | MSC | ZTC | GCC
  984.     register char *sp;    /* temp string pointer */
  985.     char buf[16];        /* time data buffer */
  986.     extern char *ctime();
  987.  
  988.     time(buf);
  989.     sp = ctime(buf);
  990.     sp[strlen(sp)-1] = 0;
  991.     return(sp);
  992. #else
  993.     return(errorm);
  994. #endif
  995. }
  996.  
  997. #if    TURBO
  998. /*    FILE Directory routines        */
  999.  
  1000. char path[NFILEN];    /* path of file to find */
  1001. char rbuf[NFILEN];    /* return file buffer */
  1002.  
  1003. /*    do a wild card directory search (for file name completion) */
  1004.  
  1005. char *PASCAL NEAR getffile(fspec)
  1006.  
  1007. char *fspec;    /* pattern to match */
  1008.  
  1009. {
  1010.     register int index;        /* index into various strings */
  1011.     register int point;        /* index into other strings */
  1012.     register int extflag;        /* does the file have an extention? */
  1013.     char fname[NFILEN];        /* file/path for DOS call */
  1014.  
  1015.     /* first parse the file path off the file spec */
  1016.     strcpy(path, fspec);
  1017.     index = strlen(path) - 1;
  1018.     while (index >= 0 && (path[index] != '/' &&
  1019.                 path[index] != '\\' && path[index] != ':'))
  1020.         --index;
  1021.     path[index+1] = 0;
  1022.  
  1023.     /* check for an extension */
  1024.     point = strlen(fspec) - 1;
  1025.     extflag = FALSE;
  1026.     while (point > index) {
  1027.         if (fspec[point] == '.') {
  1028.             extflag = TRUE;
  1029.             break;
  1030.         }
  1031.         point--;
  1032.     }
  1033.  
  1034.     /* construct the composite wild card spec */
  1035.     strcpy(fname, path);
  1036.     strcat(fname, &fspec[index+1]);
  1037.     strcat(fname, "*");
  1038.     if (extflag == FALSE)
  1039.         strcat(fname, ".*");
  1040.  
  1041.     /* and call for the first file */
  1042.     if (findfirst(fname, &fileblock, FA_DIREC) == -1)
  1043.         return(NULL);
  1044.  
  1045.     /* return the first file name! */
  1046.     strcpy(rbuf, path);
  1047.     strcat(rbuf, fileblock.ff_name);
  1048.     mklower(rbuf);
  1049.     if (fileblock.ff_attrib == 16)
  1050.         strcat(rbuf, DIRSEPSTR);
  1051.     return(rbuf);
  1052. }
  1053.  
  1054. char *PASCAL NEAR getnfile()
  1055.  
  1056. {
  1057.     register int index;        /* index into various strings */
  1058.     register int point;        /* index into other strings */
  1059.     register int extflag;        /* does the file have an extention? */
  1060.     char fname[NFILEN];        /* file/path for DOS call */
  1061.  
  1062.     /* and call for the first file */
  1063.     if (findnext(&fileblock) == -1)
  1064.         return(NULL);
  1065.  
  1066.     /* return the first file name! */
  1067.     strcpy(rbuf, path);
  1068.     strcat(rbuf, fileblock.ff_name);
  1069.     mklower(rbuf);
  1070.     if (fileblock.ff_attrib == 16)
  1071.         strcat(rbuf, DIRSEPSTR);
  1072.     return(rbuf);
  1073. }
  1074. #else
  1075. #if    MSC | ZTC
  1076. /*    FILE Directory routines        */
  1077.  
  1078. char path[NFILEN];    /* path of file to find */
  1079. char rbuf[NFILEN];    /* return file buffer */
  1080.  
  1081. /*    do a wild card directory search (for file name completion) */
  1082.  
  1083. char *PASCAL NEAR getffile(fspec)
  1084.  
  1085. char *fspec;    /* pattern to match */
  1086.  
  1087. {
  1088.     register int index;        /* index into various strings */
  1089.     register int point;        /* index into other strings */
  1090.     register int extflag;        /* does the file have an extention? */
  1091.     char fname[NFILEN];        /* file/path for DOS call */
  1092.  
  1093.     /* first parse the file path off the file spec */
  1094.     strcpy(path, fspec);
  1095.     index = strlen(path) - 1;
  1096.     while (index >= 0 && (path[index] != '/' &&
  1097.                 path[index] != '\\' && path[index] != ':'))
  1098.         --index;
  1099.     path[index+1] = 0;
  1100.  
  1101.     /* check for an extension */
  1102.     point = strlen(fspec) - 1;
  1103.     extflag = FALSE;
  1104.     while (point > index) {
  1105.         if (fspec[point] == '.') {
  1106.             extflag = TRUE;
  1107.             break;
  1108.         }
  1109.         point--;
  1110.     }
  1111.  
  1112.     /* construct the composite wild card spec */
  1113.     strcpy(fname, path);
  1114.     strcat(fname, &fspec[index+1]);
  1115.     strcat(fname, "*");
  1116.     if (extflag == FALSE)
  1117.         strcat(fname, ".*");
  1118.  
  1119.     /* and call for the first file */
  1120.     if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
  1121.         return(NULL);
  1122.  
  1123.     /* return the first file name! */
  1124.     strcpy(rbuf, path);
  1125.     strcat(rbuf, fileblock.name);
  1126.     mklower(rbuf);
  1127.     if (fileblock.attrib == 16)
  1128.         strcat(rbuf, DIRSEPSTR);
  1129.     return(rbuf);
  1130. }
  1131.  
  1132. char *PASCAL NEAR getnfile()
  1133.  
  1134. {
  1135.     register int index;        /* index into various strings */
  1136.     register int point;        /* index into other strings */
  1137.     register int extflag;        /* does the file have an extention? */
  1138.     char fname[NFILEN];        /* file/path for DOS call */
  1139.  
  1140.     /* and call for the first file */
  1141.     if (_dos_findnext(&fileblock) != 0)
  1142.         return(NULL);
  1143.  
  1144.     /* return the first file name! */
  1145.     strcpy(rbuf, path);
  1146.     strcat(rbuf, fileblock.name);
  1147.     mklower(rbuf);
  1148.     if (fileblock.attrib == 16)
  1149.         strcat(rbuf, DIRSEPSTR);
  1150.     return(rbuf);
  1151. }
  1152. #else
  1153. char *PASCAL NEAR getffile(fspec)
  1154.  
  1155. char *fspec;    /* file to match */
  1156.  
  1157. {
  1158.     return(NULL);
  1159. }
  1160.  
  1161. char *PASCAL NEAR getnfile()
  1162.  
  1163. {
  1164.     return(NULL);
  1165. }
  1166. #endif
  1167. #endif
  1168. #endif
  1169.